package net.qiqb.spring.domain.event;

import lombok.extern.slf4j.Slf4j;
import net.qiqb.core.domain.event.DomainEventPublisher;
import net.qiqb.core.domain.event.DomainEvent;
import net.qiqb.core.domain.event.DomainEventPersistence;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.LockSupport;

@Slf4j
public class SimpleDomainEventTrigger implements SmartInitializingSingleton {

    private DomainEventPersistence domainEventPersistence;

    private ApplicationContext applicationContext;

    private static Thread t;


    public static void unpark() {
        if (t == null) {
            return;
        }
        LockSupport.unpark(t);
    }

    public void start() {
        final List<DomainEventPublisher> domainEventPublisher = new ArrayList<>();
        t = new Thread(() -> {
            while (true) {
                if (domainEventPublisher.isEmpty()) {
                    final Map<String, DomainEventPublisher> domainEventPublisherMap = applicationContext.getBeansOfType(DomainEventPublisher.class);
                    domainEventPublisher.addAll(domainEventPublisherMap.values());
                }
                try {
                    final List<DomainEvent> domainEvents = domainEventPersistence.listReady();
                    if (domainEvents != null) {

                        for (DomainEvent domainEvent : domainEvents) {
                            for (DomainEventPublisher eventPublisher : domainEventPublisher) {
                                eventPublisher.publishEvent(domainEvent);
                            }
                            domainEvent.sent();
                            domainEventPersistence.sent(domainEvent.getId());
                        }

                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("推送领域事件失败，{}", e.getMessage());
                }
                LockSupport.park();
            }
        });
        t.start();
    }


    @Autowired
    public void setDomainEventPersistence(DomainEventPersistence domainEventPersistence) {
        this.domainEventPersistence = domainEventPersistence;
    }

    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public void afterSingletonsInstantiated() {
        this.start();
    }
}
